package ooo.reindeer.cedf.components.queue;

import ooo.reindeer.cedf.Event;
import ooo.reindeer.cedf.components.handler.IEventHandler;
import ooo.reindeer.commons.Property;
import ooo.reindeer.logging.ILogger;
import ooo.reindeer.logging.LogUtil;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MemoryQueue implements IEventQueue {

    private static final ILogger logger = LogUtil.getLogger(MemoryQueue.class);

    private final BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
    private IEventHandler handler;

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    private boolean isQuit = false;

    Property config;
    String id;

    private final Thread thread = new Thread() {

        public void run() {
            logger.debug("run():");
            while (!isQuit) {
                try {
                    IEventHandler tempHandler=handler;
                    if (tempHandler == null) {
                        try {
                            lock.lock();
                            condition.await();
                        }finally {
                            lock.unlock();
                        }

                    } else {
                        String event = queue.poll(1, TimeUnit.SECONDS);

                        logger.trace("queue.take():event=[{}]", event);
                        handler.onEvent(Event.fromString(event));
                    }
                } catch (InterruptedException e) {
                    break;
                }
            }
        }

    };

    @Override
    public boolean init(String id,Property config) {
        logger.debug("init:id=[{}]	config=[{}]", id, config);

        this.id=id;
        this.config=config;

        thread.setDaemon(true);
        start();
        return true;
    }

    @Override
    public boolean start() {
        thread.start();
        return true;
    }

    @Override
    public boolean stop() {
        isQuit = true;
        thread.interrupt();
        return true;
    }

    @Override
    public boolean offer(Event event) {
        logger.trace("offer:event=[{}]", event);
        return queue.offer(event.toString());
    }

    @Override
    public Event poll() {
        String eventString= queue.poll();
        if(eventString==null) {
            return null;
        }
        return Event.fromString(eventString);
    }

    @Override
    public boolean regEventHandler(IEventHandler handler) {
        logger.debug("regEventHandler:handler=[{}]", handler);
        if (handler != null) {
            this.handler = handler;
            try {
                lock.lock();
                condition.signalAll();
            }finally {
                lock.unlock();
            }

            return true;
        } else {
            return false;
        }

    }

    @Override
    public boolean unRegEventHandler() {
        thread.interrupt();
        handler = null;
        return true;
    }

    @Override
    public long size() {
        return queue.size();
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public Property getConfig() {
        return config;
    }
}
